#-*- coding: utf8 -*-

import socket
from sys import stdin
from select import select
import sys
import xml.etree.ElementTree as etree
from time import sleep

reply_to = ""

#### FUNCTIONS ####

## HELPER: human readable
def human_filesize(size):
    num = float(size)
    for x in ['bytes','KB','MB','GB','TB']:
        if ( num < 1024.0 ):
            return "%3.1f %s" % (num, x)
        num /= 1024.0         

## TODO: Description
def xml_reader(data):
    global reply_to
    commands = data.split('<>')
    for command in commands:
        command = command.strip()
        if ( command == "" ):
            continue
        
        if ( command.startswith("<") ):
            
#            print "    < " + command + " >" ## XXX debug output
            tree = etree.fromstring(command)
#            root = tree.getroot()

            ## BRANCH: LIST, known users
            if ( tree.tag == "users" ):
                print "[USERS]"
                for user_element in tree.findall('user'):
                    user_name = user_element.findtext('name')
                    connected = user_element.findtext('connected')
                    connection_flag = "│ "
                    if ( connected == "1" ):
                        connection_flag = "├─"
                    elif ( connected in "23456" ):
#                        connection_flag = "├.. "
                        connection_flag = "├(" + connected + ").. "
                    elif ( connected in "78" ):
                        connection_flag = "├X "
                    print connection_flag+user_name

            ## BRANCH: STAT, filetransfers
            elif ( tree.tag == "filetransfers" ):
                for direction in ('incoming', 'outgoing'):
                    for transfer_element in tree.find(direction).findall('file'):
                        
                        ## read out xml parameters
                        file_name = transfer_element.findtext('filename')
                        partner = transfer_element.findtext('partner')
                        transferred = transfer_element.findtext('transferred')
                        size = transfer_element.findtext('size')
                        state = transfer_element.findtext('state')
                        progress = 0
                        
                        ## calculate progress in percent
                        if int(size) > 0:
                            if int(transferred) <= 0:
                                progress = "0"
                            else:
                                progress = int(float(transferred) / float(size) * 100)
                        
                        if direction == "incoming":
                            direc = "FROM"
                            DIREC = "INCOMING"
                        else:
                            direc = "TO"
                            DIREC = "OUTGOING"
                        
                        h_transferred = human_filesize(transferred)
                        h_size = human_filesize(size)
                        
                        print "["+DIREC+"]"
                        print "├─FILE:", file_name+",", h_size
                        print "├─"+direc+":", partner
                        print "└─PROGRESS:", h_transferred+"/"+h_size, "("+str(progress)+"%),", state

            ## BRANCH: incoming chat message
            elif ( tree.tag == "chat" ):
                msg_sender = tree.findtext('from')
                msg_receiver = tree.findtext('to')
                msg_time = tree.findtext('time_stamp')
                msg_text = tree.findtext('text')
                print "[CHAT] ("+msg_time+")", msg_sender+":", msg_text
                
                reply_to = msg_sender

            ## BRANCH: transmission confirmation of chat message
            elif (tree.tag == "chatecho" ):
                print "message SENT"

            ## BRANCH: INFO (etc) messages
            elif (tree.tag in ("info", "warn", "debug")):
                print "[" + tree.tag.upper() + "]\t" + tree.text


            ## BRANCH: --- not recognized ---
            else:
                    print command
        else:
            print command

#### [FUNCTIONS] ####

## parameter
if ( len(sys.argv) < 2 ):
    print "Socket Adresse..."
    exit(1)
SOCK_ADDR = sys.argv[1]

## XXX hack
sleep(0.5)

## main
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(SOCK_ADDR)
print "backend ok"
DONE = 0

listen_on = [stdin, sock]
while not DONE:
    (rr, wr, er) = select(listen_on, [], [])
    
    for fd in rr:
        ## socket
        if ( fd == sock ):
            data = ""
            while True:
                inc = sock.recv(4096)
                data += inc
                if len(inc) < 4096: ## TODO corner cases checken, was wenn genau 4k?
                    break
            
            ## BRANCH: data via socket
            if data:
                xml_reader(data)
            
            ## BRANCH: socket closed by the other side
            else:
                print ">> Omnibus has closed the connection. <<"
                listen_on.remove(sock)
                sock.close()
                sock = 0

        ## für die Eingabe wär sowas wie > an jedem Zeilenanfang cool... Müsste man aber schauen, wie man damit umgeht, dass ja jederzeit Benachrichtigungen von omnibus reinploppen klönnen ~~~Karin_20120104
        ## stdin
        elif ( fd == stdin ):
            user_input = fd.readline().strip()
            omnibus_cmd = user_input
            
            ## BRANCH: help
            ## outcommented commands are to come ~~~Karin_20120104
            if ( user_input == "help" ):
                print "You can use the following commands:"
                print "help ........................... prints help list"
                print "LIST ........................... prints user list"
                print "STAT ........................... prints transfer list"
                print "CONN <username> ................ starts a connection with user <username>"
                #print "push <file_path> <username> .... sends a file to user <username>"
                #print "showfiles <username> ........... prints user <username>'s available files
                #print "pull" ## THAT has to be done nicely... ideas welcomed \(°ω°)/ ~~~Karin_20120103
                #print "offer <file_path> [<username>] . copies file into public directory or into private directory for user if <username> is specified"
                #print "withdraw <file> [<username>]" ## only makes sense if file was offered to user... think about a better solution ~~~Karin_20120103
                #print "accept <file>"
                #print "pause <file_transfer>"
                #print "pauseall"
                #print "start/resume <file_transfer>"
                print "chat <username> <text> ......... sends a chat message to user <username>"
                print "reply <text> ................... sends a chat message to the user from whom you received the last message"
                print "quit ........................... quits omnibus client"
                print "More to come. :-)"
                
                omnibus_cmd = ""

            ## BRANCH: chat ~~~Karin_20120104
            elif ( user_input.startswith("chat") ):
                ## FIXME: doesn't work properly if username contains white spaces ~~~Karin_20120103
                chat_param = user_input.split(None, 2)
                chat_partner = chat_param[1]
                chat_message = chat_param[2]
                
                chat = etree.Element('chat')
                
                to = etree.SubElement(chat, 'to')
                to.text = chat_partner
                
                text = etree.SubElement(chat, 'text')
                text.text = chat_message
                
                omnibus_cmd = etree.tostring(chat, encoding = 'ascii')

            ## BRANCH: reply ~~~Karin_20120104
            elif ( user_input.startswith("reply") ):
                
                if ( not reply_to ):
                    print "There is no message to reply to. Please use \"chat\" to send a message."
                    omnibus_cmd = ""
                
                else:
                    chat_param = user_input.split(None, 1)
                    chat_message = chat_param[1]
                    chat_partner = reply_to
                    
                    chat = etree.Element('chat')
                    
                    to = etree.SubElement(chat, 'to')
                    to.text = chat_partner
                    
                    text = etree.SubElement(chat, 'text')
                    text.text = chat_message
                    
                    omnibus_cmd = etree.tostring(chat, encoding = 'ascii')
            
            
            ## BRANCH: pushsync  XXX experimentell
            elif ( user_input.startswith("pushsync") ):
                comm, name, path = user_input.split(None, 2)
                
                sync = etree.Element('pushsync')
                
                elem_partner = etree.SubElement(sync, 'name')
                elem_partner.text = name
                
                elem_path = etree.SubElement(sync, 'path')
                elem_path.text = path
                
                omnibus_cmd = etree.tostring(sync, encoding = 'ascii')
                
#                print omnibus_cmd

            ## BRANCH: pullsync  XXX experimentell
            elif ( user_input.startswith("pullsync") ):
                comm, name, path = user_input.split(None, 2)
                
                sync = etree.Element('pullsync')
                
                elem_partner = etree.SubElement(sync, 'name')
                elem_partner.text = name
                
                elem_path = etree.SubElement(sync, 'path')
                elem_path.text = path
                
                omnibus_cmd = etree.tostring(sync, encoding = 'ascii')
                
                print omnibus_cmd

            
            ## BRANCH: legacy non-xml commands
            elif ( not user_input.startswith("<") ):
                omnibus_cmd = "<legacy>" + user_input + "</legacy>"
            
            
            #####  ----> send command to the omnibus backend
            if ( omnibus_cmd and sock ):
                sock.send(omnibus_cmd + "<>") # TODO: Daten auswerten und in XML übersetzen (muss gleichzeitig auch in Omnibus selbst gemacht werden)
            if ( user_input == "quit" ):
                DONE = 1


## finish
if sock:
    sock.close()
  
